/* 
 * File:   meshimpl_surf3d.h
 * Author: boyan
 *
 * Created on March 27, 2009, 4:26 PM
 */

#ifndef _MESHIMPL_SURF3D_H
#define	_MESHIMPL_SURF3D_H

#include "Mesh_grid3d.h"

#include <vector>
#include <map>
#include <cassert>

// this class takes a grid3d and provides an embedded surface
//  if instantiated with Mesh_surf3d(grid3d_t &grid, std::vector<char> &ls)
//  then ls must be the levelsets such that nodes with ls>0 are inside the
//  surface, nodes with ls==0 form a closed surface, nodes with ls<0 are
//  outside the surface.

class Mesh_surf3d : public Mesh_grid3d
{
protected:
    std::vector<bool> surf_nodes;
    std::vector<bool> surf_faces;
    std::vector<bool> swap;

    void surf_init(const std::vector<int> &in_elems);
    bool is_face_on_surface(int fid);
    bool is_node_on_surface(int nid);

public:

    template <typename LSType>
    Mesh_surf3d(grid3d_t &grid, std::map<Mesh::VertexHandle, LSType> &ls,
                LSType value = (LSType) 0);

    // makes surface from outer boundary of grid
    Mesh_surf3d(grid3d_t &grid);

    virtual void get_all_elements(msq_std::vector<ElementHandle>& elements,
                                  Mesquite::MsqError& err);
    virtual void get_all_vertices(msq_std::vector<VertexHandle>& vertices,
                                  Mesquite::MsqError& err);
    virtual void vertices_get_attached_elements
    (const VertexHandle* vert_array, size_t num_vertex,
     msq_std::vector<ElementHandle>& elements,
     msq_std::vector<size_t>& offsets, Mesquite::MsqError& err);

    virtual void elements_get_attached_vertices
    (const ElementHandle *elem_handles, size_t num_elems,
     msq_std::vector<VertexHandle>& vert_handles,
     msq_std::vector<size_t>& offsets, Mesquite::MsqError &err);

    virtual void elements_get_topologies
    (const ElementHandle *element_handle_array,
     Mesquite::EntityTopology *element_topologies,
     size_t num_elements, Mesquite::MsqError &err);

    virtual Mesquite::VertexIterator* vertex_iterator(Mesquite::MsqError &err)
    {
        return new bool_iterator<node2handle > (surf_nodes);
    };

    virtual Mesquite::ElementIterator* element_iterator(Mesquite::MsqError &err)
    {
        return new bool_iterator<elem2handle > (surf_faces);
    };

protected:

    template <Mesquite::Mesh::EntityHandle(*index2handle)(int) >
    class bool_iterator : public Mesquite::EntityIterator
    {
        std::vector<bool> &is_counted;
        int pos;
    public:

        bool_iterator(std::vector<bool> &a) : is_counted(a)
        {
            restart();
        }

        virtual void restart()
        {
            pos = -1;
            this->operator ++();
        }

        virtual Mesquite::Mesh::EntityHandle operator*() const
        {
            return index2handle(pos);
        }

        virtual void operator++()
        {
            do
            {
                ++pos;
            }
            while ((!is_counted[pos]) && (!is_at_end()));
        }

        virtual bool is_at_end() const
        {
            return pos >= (int) is_counted.size();
        }
    };
};

inline bool Mesh_surf3d::is_face_on_surface(int fid)
{
    return surf_faces[fid];
}

inline bool Mesh_surf3d::is_node_on_surface(int nid)
{
    return surf_nodes[nid];
}

template <typename LSType>
Mesh_surf3d::Mesh_surf3d(grid3d_t &grid,
                         std::map<Mesh::VertexHandle, LSType> &ls, LSType value)
: Mesh_grid3d(grid)
{
    assert((int) ls.size() == grid.NN);

    size_t count = 0;
    std::vector<int> in_el;
    in_el.reserve(grid.NEL);
    for (int i = 0; i < grid.NEL; i++)
    {
        elem_t &el = grid.elems[i];
        int j;
        for (j = 0; j < 4; j++)
        {
            Mesh::VertexHandle h = node2handle(el.nodes[j]);
            if (ls[h] < value)
                break;
        }
        if (j < 4)
        {
            ++count;
            in_el.push_back(i);
        }
    }
    assert(count == in_el.size());
    this->surf_init(in_el);
}


#endif	/* _MESHIMPL_SURF3D_H */

